#pragma once

#include<iostream>
#include<queue>
#include<pthread.h>
#include<unistd.h>
#include"Task.hpp"
using namespace std;
#define SIZE 10
template<class T>
class BlockQueue
{
   public:
   BlockQueue(int maxbq=SIZE):maxbq_(maxbq)
   {
      pthread_mutex_init(&lock,nullptr);//初始化锁
      pthread_cond_init(&c_cond,nullptr);//初始化条件变量
      pthread_cond_init(&p_cond,nullptr);
      low_water=2;
      high_water=8;
   }
   void push(T data)//生产
   {
      pthread_mutex_lock(&lock);
      while(q.size()==maxbq_)//这里要用while而不是if,避免出现伪唤醒情况
      {
         //如果阻塞队列满了,就去条件队列排队等待调度
         pthread_cond_wait(&p_cond,&lock);//去等待的同时会把锁释放掉
      }
      //1.阻塞队列不为空   2.生产者进程被唤醒
      q.push(data);
     // cout<<"生产了一个数据 "<<data<<endl;
     // if(q.size()>high_water)
      pthread_cond_signal(&c_cond);//生产后可以将消费者进程唤醒 被唤醒的进程重新申请锁
      pthread_mutex_unlock(&lock);
   }
   T pop()
   {
      pthread_mutex_lock(&lock);
      while(q.size()==0)
      {
         pthread_cond_wait(&c_cond,&lock);
      }
      T x=q.front();
      q.pop();
      //cout<<"消费了一个数据 "<<x<<endl;
      //if(q.size()<low_water)
      pthread_cond_signal(&p_cond);
      pthread_mutex_unlock(&lock);
      return x;
   }
   ~BlockQueue()
   {
      //回收
      pthread_mutex_destroy(&lock);
      pthread_cond_destroy(&c_cond);
      pthread_cond_destroy(&p_cond);
   }
   private:
   queue<Task>q;
   int maxbq_;//设置阻塞队列的容量
   pthread_mutex_t lock;//两个线程共用一把锁  互斥
   pthread_cond_t c_cond;//消费者条件变量 不为0才能消费
   pthread_cond_t p_cond;//生产者条件变量 不为满才能生产  
   int low_water;//设置水位线
   int high_water;
};